home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Storage / Bento / CM / CMObjOps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  33.7 KB  |  866 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:         CMObjOps.c  
  3.  
  4.     Contains:    Container Manager Object Operations
  5.  
  6.     Written by:    Ira L. Ruben
  7.  
  8.     Owned by:    Ed Lai
  9.  
  10.     Copyright:    © 1991 - 1996 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.  
  14.          <3>     8/13/96    DM        1362809: disable containers on error
  15.          <2>     1/15/96    TJ        Cleaned Up
  16.          <4>     2/15/95    EL        1182275: Move CMKeepObject to CMRefOps
  17.                                     because CMKeepObject depends on references.
  18.          <3>     12/9/94    EL        #1182275 Now we garbage collect property
  19.                                                     and type object, so need to track their
  20.                                                     usage.
  21.          <2>     8/26/94    EL        #1181622 Ownership update.
  22.          <2>     3/17/94    EL        Add CMKeepObject call. #1149983
  23.          <1>      2/3/94    EL        first checked in
  24.          <8>     1/25/94    EL        Undo the last change.
  25.          <7>     1/21/94    EL        Disable checking of useCount in
  26.                                                     CMDeleteObject until after alpha.
  27.          <6>    11/10/93    EL        Add CMCountProperties call.
  28.          <5>     10/6/93    EL        Rename CMGetAdjacentXXXX to getAdjacentXXXX
  29.                                                     and static near.
  30.          <4>     10/4/93    EL        Add CMGetPrevObject and CMGetPrevObjectWithProperty, 
  31.                                                      replace CMGetPrevObjectProperty
  32.          <3>     9/27/93    VL        Added CMGetPrevObjectProperty.
  33.          <2>      9/8/93    VL        Added GetObject and GetObjectID.
  34.  
  35.     To Do:
  36. */
  37.  
  38. /*---------------------------------------------------------------------------*
  39.  |                                                                           |
  40.  |                           <<<  CMObjOps.c   >>>                           |
  41.  |                                                                           |
  42.  |                    Container Manager Object Operations                    |
  43.  |                                                                           |
  44.  |                               Ira L. Ruben                                |
  45.  |                                 12/15/91                                  |
  46.  |                                                                           |
  47.  |                  Copyright Apple Computer, Inc. 1991-1994                 |
  48.  |                           All rights reserved.                            |
  49.  |                                                                           |
  50.  *---------------------------------------------------------------------------*
  51.  
  52.  All Container Manager API routines dealing with objects (not their properties, types, 
  53.  or values) are handled in this file.  Properties and types are also objects, but they 
  54.  are treated separately.
  55.  
  56.  An object is defined in terms of its properties.  The properties are defined in terms of
  57.  the typed values.  Here we mainly create and access just the objects.  Internally they
  58.  are kept distince by object ID's.  From the API user's point of view objects are 
  59.  manipulated through refNums.
  60. */
  61.  
  62.  
  63. #include <stddef.h>
  64. #include <string.h>
  65. #include <stdio.h>
  66.  
  67. #ifndef __CMTYPES__
  68. #include "CMTypes.h"
  69. #endif
  70. #ifndef __CM_API__
  71. #include "CMAPI.h"
  72. #endif
  73. #ifndef __LISTMGR__
  74. #include "ListMgr.h"
  75. #endif
  76. #ifndef __TOCENTRIES__
  77. #include "TOCEnts.h"   
  78. #endif
  79. #ifndef __TOCOBJECTS__
  80. #include "TOCObjs.h"   
  81. #endif
  82. #ifndef __GLOBALNAMES__
  83. #include "GlbNames.h"   
  84. #endif
  85. #ifndef __CONTAINEROPS__
  86. #include "Containr.h"  
  87. #endif
  88. #ifndef __HANDLERS__
  89. #include "Handlers.h"
  90. #endif
  91. #ifndef __UPDATING__
  92. #include "Update.h"  
  93. #endif
  94. #ifndef __SESSIONDATA__
  95. #include "Session.h"          
  96. #endif
  97. #ifndef __ERRORRPT__
  98. #include "ErrorRpt.h"      
  99. #endif
  100. #ifndef __UTILITYROUTINES__
  101. #include "Utility.h"        
  102. #endif
  103.                                                                 
  104.                                                                     CM_CFUNCTIONS
  105.  
  106. /* The following generates a segment directive for Mac only due to 32K Jump Table             */
  107. /* Limitations.  If you don't know what I'm talking about don't worry about it.  The        */
  108. /* default is not to generate the pragma.  Theoritically unknown pragmas in ANSI won't    */
  109. /* choke compilers that don't recognize them.                                                                                        */
  110.  
  111. #if CM_MPW
  112. #pragma segment CMObjectOps
  113. #endif
  114.                                                                     
  115.  
  116. struct GetGNameComArea {                    /* CMGetGlobalName() object walking comm area layout:    */
  117.     TOCValuePtr      theValue;                /*        the first (should be only) global name value        */
  118.     CM_USHORT             nbrOfGlobalNames;/*        count of nbr of global names found in object        */
  119. };
  120. typedef struct GetGNameComArea GetGNameComArea, *GetGNameComAreaPtr;
  121.  
  122.  
  123. /*-----------------------------------*
  124.  | CMNewObject - create a new object |
  125.  *-----------------------------------*
  126.  
  127.  A new object is created in the specified container and its refNum returned.  At this
  128.  point the object is considered as "undefined".  It has no properties and thus no values.
  129. */
  130.  
  131. CMObject CM_FIXEDARGS CMNewObject(CMContainer targetContainer)
  132. {
  133.     TOCObjectPtr theObject;
  134.     ContainerPtr container = (ContainerPtr)targetContainer;
  135.     
  136.     NOPifNotInitialized(NULL);                                                /* NOP if not initialized!                    */
  137.     
  138.     /* The object is created as "undefined".  CMNewValue() will mark it defined because     */
  139.     /* at that time it will get a property and a value.                                                                        */
  140.     
  141.     theObject = cmDefineObject(container, container->nextUserObjectID, 0, 0, NULL, 0, 0, 
  142.                                                           UndefinedObject | ObjectObject, NULL);
  143.  
  144.     if (theObject) {
  145.         theObject->useCount = 1;                                                /* initial use of this object                */
  146.         IncrementObjectID(container->nextUserObjectID);    /* set to use next available user ID*/
  147.     }
  148.     
  149.     return ((CMObject)theObject);
  150. }
  151.  
  152.  
  153. /*----------------------------------------------------------------------------------*
  154.  | getAdjacentObject - get adjacent object in the container by increasing object ID |
  155.  *----------------------------------------------------------------------------------*
  156.  
  157.  This routine returns the refNum for the next/previous object in the container 
  158.  following/preceding currObject. If currObject is NULL, the refNum for the first/last
  159.  object is returned.  If currObject is not NULL, the object with the next highest ID 
  160.  next lowerest is returned.  NULL is returned if there are no more objects following/preceding
  161.  currObject.
  162.  
  163.  currObject is generally a refNum previously returned from this routine.  Successive calls
  164.  to this routine will thus yield all the objects in the container.
  165. */
  166.  
  167. static CMObject CM_NEAR getAdjacentObject(CMContainer targetContainer, 
  168.                                                                                     CMObject currObject,
  169.                                                                                     Boolean forward)
  170. {
  171.     TOCObjectPtr theObject;
  172.     ContainerPtr container = (ContainerPtr)targetContainer;
  173.     
  174.     NOPifNotInitialized(NULL);                                                /* NOP if not initialized!                    */
  175.     
  176.     if (currObject == NULL) {                                                    /* NULL ==> use head/tail of list                */
  177.         if (forward)
  178.             theObject = (TOCObjectPtr)cmGetMasterListHead(container->toc, ObjectObject);
  179.         else
  180.             theObject = (TOCObjectPtr)cmGetMasterListTail(container->toc, ObjectObject);
  181.         if (theObject) ++theObject->useCount;                        /* bump use count for next object        */
  182.         return ((CMObject)theObject);
  183.     }
  184.     
  185.     ExitIfBadObject(currObject, NULL);                                /* validate currObject                            */
  186.     
  187.     { ContainerPtr other = ((TOCObjectPtr)currObject)->container;
  188.         if (container->targetContainer != other->targetContainer) {
  189.             Container_Disable(other);
  190.             Container_Disable(container);
  191.             ERROR3(CM_err_BadContainer, "object", CONTAINERNAMEx(other), CONTAINERNAMEx(container));
  192.             return (NULL);
  193.         }
  194.     }
  195.     
  196.     /* In our implementation the objects are already chained in sorted order.  So all we     */
  197.     /* have to do is follow the chain (or is it a yellow brick road?).                                        */
  198.     
  199.     if (forward)
  200.         theObject = ((TOCObjectPtr)currObject)->nextObject;
  201.     else
  202.         theObject = ((TOCObjectPtr)currObject)->prevObject;
  203.     if (theObject) ++theObject->useCount;                            /* bump use count for adjacent object    */
  204.     
  205.     return ((CMObject)theObject);                                            /* return NULL or next object refNum*/
  206. }
  207.  
  208. /*----------------------------------------------------------------------------*
  209.  | CMGetNextObject - get next object in the container by increasing object ID |
  210.  *----------------------------------------------------------------------------*
  211.  
  212.  Just call getAdjacentObject with forward = true.
  213. */
  214.  
  215. CMObject CM_FIXEDARGS CMGetNextObject(CMContainer targetContainer, CMObject currObject)
  216.  
  217. {
  218.     return getAdjacentObject(targetContainer, currObject, true);
  219. }
  220.  
  221. /*--------------------------------------------------------------------------------*
  222.  | CMGetPrevObject - get previous object in the container by increasing object ID |
  223.  *--------------------------------------------------------------------------------*
  224.  
  225.  Just call getAdjacentObject with forward = false.
  226. */
  227.  
  228. CMObject CM_FIXEDARGS CMGetPrevObject(CMContainer targetContainer, CMObject currObject)
  229.  
  230. {
  231.     return getAdjacentObject(targetContainer, currObject, false);
  232. }
  233.  
  234. /*--------------------------------------------------------------------------------*
  235.  | getAdjacentObjectProperty - get the adjacent property for the specified object |
  236.  *--------------------------------------------------------------------------------*
  237.  
  238.  This routine returns the refNum for the next/prev property defined for the given object.  If
  239.  currProperty is NULL, the refNum for the first/last property for the object is returned.  If 
  240.  it is not NULL, the next/prev property refNum following currProperty is returned.
  241.  
  242.  currProperty is generally a refNum previously returned from this routine. Successive
  243.  calls to this routine will thus yield all the properties for the given object.
  244. */
  245.  
  246. static CMProperty CM_NEAR getAdjacentObjectProperty(CMObject theObject, CMProperty currProperty, 
  247.                                                                                                         Boolean forward)
  248. {
  249.     TOCObjectPtr      theAdjacentObject;
  250.     TOCPropertyPtr theProperty;
  251.     ContainerPtr      container;
  252.     
  253.     ExitIfBadObject(theObject, NULL);                                    /* validate theObject                                */
  254.  
  255.     container = ((TOCObjectPtr)theObject)->container;
  256.     
  257.     /* If currProperty is NULL we return the object with the property ID taken from the        */
  258.     /* first/last property on theObject.                                                                                                    */
  259.     
  260.     if (currProperty == NULL)    {                                                /* NULL ==> use head of list                */
  261.         if (forward)
  262.             theProperty = (TOCPropertyPtr)cmGetListHead(&((TOCObjectPtr)theObject)->propertyList);
  263.         else
  264.             theProperty = (TOCPropertyPtr)cmGetListTail(&((TOCObjectPtr)theObject)->propertyList);
  265.         return ((CMProperty)cmFindObject(container->toc, theProperty->propertyID));
  266.     }
  267.     
  268.     ExitIfBadProperty(currProperty, NULL);                        /* validate currProperty                        */
  269.     
  270.     { ContainerPtr other = ((TOCObjectPtr)currProperty)->container;
  271.         if (container->targetContainer != other->targetContainer) {
  272.             Container_Disable(container);
  273.             Container_Disable(other);
  274.             ERROR2(CM_err_2Containers, CONTAINERNAMEx(container),
  275.                                                                  CONTAINERNAMEx(other));
  276.             return (NULL);
  277.         }
  278.     }
  279.     
  280.     /* Here we ant to find the next/prev property for the object.  Since currProperty is     */
  281.     /* not NULL, it points to an object because it's a refNum.  Remember it is not a             */
  282.     /* TOCPropertyPtr.  What we have to do is use the property ID to find the property        */
  283.     /* (a real TOCPropertyPtr) we found the last time this routine was called.  Then we        */
  284.     /* simply get the next/prev on the list to get the next/prev property ID.                            */
  285.     
  286.     theProperty = cmGetObjectProperty((TOCObjectPtr)theObject, /* find prop ID for object    */
  287.                                                                         ((TOCObjectPtr)currProperty)->objectID);
  288.     if (theProperty) {                                                                /* if we found ID on the list...        */
  289.         if (forward)
  290.             theProperty = (TOCPropertyPtr)cmGetNextListCell(theProperty); /* ...get next            */
  291.         else
  292.             theProperty = (TOCPropertyPtr)cmGetPrevListCell(theProperty); /* ...get previous    */
  293.         if (theProperty) {                                                            /* if there's a next property...        */
  294.             theAdjacentObject = cmFindObject(container->toc, theProperty->propertyID); /* get obj    */
  295.             if (theAdjacentObject) ++theAdjacentObject->useCount;    /* bump its use count                */
  296.             return ((CMProperty)theAdjacentObject);                /* give caller the property object    */
  297.         }
  298.     }
  299.     
  300.     return (NULL);
  301. }
  302.  
  303. /*--------------------------------------------------------------------------*
  304.  | CMGetNextObjectProperty - get the next property for the specified object |
  305.  *--------------------------------------------------------------------------*
  306.  
  307.  Just call getAdjacentObjectProperty with forward = true.
  308. */
  309.  
  310. CMProperty CM_FIXEDARGS CMGetNextObjectProperty(CMObject theObject, CMProperty currProperty)
  311. {
  312.     return getAdjacentObjectProperty(theObject, currProperty, true);
  313. }
  314.  
  315. /*------------------------------------------------------------------------------*
  316.  | CMGetPrevObjectProperty - get the previous property for the specified object |
  317.  *------------------------------------------------------------------------------*
  318.  
  319.  Just call getAdjacentObjectProperty with forward = false.
  320. */
  321.  
  322. CMProperty CM_FIXEDARGS CMGetPrevObjectProperty(CMObject theObject, CMProperty currProperty)
  323. {
  324.     return getAdjacentObjectProperty(theObject, currProperty, false);
  325. }
  326.  
  327. /*-----------------------------------------------------------------------------------------*
  328.  | getAdjacentObjectWithProperty - get the adjacent object that has the specified property |
  329.  *-----------------------------------------------------------------------------------------*
  330.  
  331.  This routine returns the refNum for the next/previous object in the container that has the 
  332.  given property.  If currObject is NULL, the search starts with the first/last object in the 
  333.  container.  If it is not NULL the search starts with the object immediately following/preceding
  334.  currObject.  If there is no next/previous object with the given property, NULL is returned. 
  335.  
  336.  currObject is generally a refNum previously returned from this routine. Successive calls
  337.  to this routine will thus yield all the objects with the given property.
  338.  */
  339.  
  340. static CMObject CM_NEAR getAdjacentObjectWithProperty(CMContainer targetContainer,
  341.                                                                                                     CMObject currObject, CMProperty property,
  342.                                                                                                     Boolean forward)
  343. {
  344.     ContainerPtr container = (ContainerPtr)targetContainer;
  345.     TOCObjectPtr theObject = (TOCObjectPtr)currObject;
  346.     
  347.     NOPifNotInitialized(NULL);                                                    /* NOP if not initialized!                */
  348.     
  349.     /* If we are given a non-NULL currObject, then start up the search with the next             */
  350.     /* object following that.  If currObject is NULL we start our search with the first        */
  351.     /* object.                                                                                                                                                        */
  352.     
  353.     if (forward) {
  354.         if (theObject != NULL) {                                                        /* if we have a starting object...*/
  355.             ExitIfBadObject(theObject, NULL);                                    /* ...validate theObject                    */
  356.             theObject = theObject->nextObject;                                /* ...get next object                            */
  357.             if (theObject == NULL) return (NULL);                            /* return NULL if no more objects    */
  358.         } 
  359.         else
  360.             theObject = cmGetMasterListHead(container->toc, ObjectObject);/* get first object        */
  361.     } 
  362.     else {
  363.         if (theObject != NULL) {                                                        /* if we have a starting object...*/
  364.             ExitIfBadObject(theObject, NULL);                                    /* ...validate theObject                    */
  365.             theObject = theObject->prevObject;                                /* ...get prev object                            */
  366.             if (theObject == NULL) return (NULL);                            /* return NULL if no more objects    */
  367.         } 
  368.         else
  369.             theObject = cmGetMasterListTail(container->toc, ObjectObject);/* get first object        */
  370.     }
  371.  
  372.     ExitIfBadProperty(property, NULL);                                    /* ...validate property                        */
  373.     
  374.     { ContainerPtr other = ((TOCObjectPtr)property)->container;
  375.         if (container->targetContainer != other->targetContainer) {
  376.             Container_Disable(container);
  377.             Container_Disable(other);
  378.             ERROR2(CM_err_2Containers, CONTAINERNAMEx(container),
  379.                                                                  CONTAINERNAMEx(other));
  380.             return (NULL);
  381.         }
  382.     }
  383.     
  384.     /* Starting with the first object or the next one after currObject we check each             */
  385.     /* object on the object chain to see if it has a property with the property ID of the */
  386.     /* given property object (descriptor). If it is found, the object pointer is returned.*/
  387.     /* If not, NULL is returned. This is easy to do since we already got a routine named    */
  388.     /* that scans an object for a property ID.                                                                                        */
  389.     
  390.     while (theObject) {
  391.         if (cmGetObjectProperty(theObject, ((TOCObjectPtr)property)->objectID) != NULL) {
  392.             ++theObject->useCount;                                                    /* if found, bump obj's use count    */
  393.             return ((CMObject)theObject);                                        /* give refNum back to user                */
  394.         }
  395.         if (forward)
  396.             theObject = theObject->nextObject;                                /* not found, keep looking                */
  397.         else
  398.             theObject = theObject->prevObject;                                /* not found, keep looking                */
  399.     }
  400.  
  401.     return (NULL);                                                                            /* not found                                             */
  402. }
  403.  
  404. /*-----------------------------------------------------------------------------------*
  405.  | CMGetNextObjectWithProperty - get the next object that has the specified property |
  406.  *-----------------------------------------------------------------------------------*
  407.  
  408.  Just call getAdjacentObjectWithProperty with forward = true.
  409.  */
  410.  
  411. CMObject CM_FIXEDARGS CMGetNextObjectWithProperty(CMContainer targetContainer,
  412.                                                                                                     CMObject currObject, CMProperty property)
  413. {
  414.     return getAdjacentObjectWithProperty(targetContainer, currObject, property, true);
  415. }
  416.  
  417. /*-------------------------------------------------------------------------------------------*
  418.  | CMGetPrevObjectWithProperty - get the previous object that has the specified property |
  419.  *-------------------------------------------------------------------------------------------*
  420.  
  421.  Just call getAdjacentObjectWithProperty with forward = false.
  422.  */
  423.  
  424. CMObject CM_FIXEDARGS CMGetPrevObjectWithProperty(CMContainer targetContainer,
  425.                                                                                                     CMObject currObject, CMProperty property)
  426. {
  427.     return getAdjacentObjectWithProperty(targetContainer, currObject, property, false);
  428. }
  429.  
  430. #if 0
  431. /*--------------------------------------------------------*
  432.  | CMGetReferenceData - create a "reference" to an object |
  433.  *--------------------------------------------------------*
  434.  
  435.  Creates a "reference" to an object (refNum), referencedObject, as data, theReferenceData,
  436.  to be written as (part of) the value data for the specified value.  The function returns
  437.  the input pointer to theReferenceData.  The caller should write the data to the value
  438.  possibly along with other data.  The size of this data is determined by the size of the
  439.  CMReference type, i.e., sizeof(CMReference).
  440.  
  441.  The returned data is in a form suitable for retrival by CMGetReferencedObject() to 
  442.  convert the data back to the object refNum.
  443. */
  444.  
  445. CMReference CM_PTR * CM_FIXEDARGS CMGetReferenceData(CMValue value,
  446.                                                                                                          CMObject referencedObject,
  447.                                                                                                           CMReference CM_PTR theReferenceData)
  448. {
  449.     ContainerPtr container;
  450.     
  451.     ExitIfBadValue(value, NULL);                                        /* validate value                                            */
  452.     ExitIfBadObject(referencedObject, NULL);                /* validate referencedObject                    */
  453.  
  454.     container = ((TOCValueHdrPtr)value)->container;
  455.     
  456.     ContainerPtr other = ((TOCObjectPtr)referencedObject)->container;
  457.     if (container->targetContainer != other->targetContainer) {
  458.         Container_Disable(container);
  459.         Container_Disable(other);
  460.         ERROR2(CM_err_CantReference, CONTAINERNAMEx(container),
  461.                                                                  CONTAINERNAMEx(other));
  462.         return (NULL);
  463.     }
  464.     
  465.     /*                         -- "DANGER WILL ROBINSON" --                                                             */
  466.     
  467.     /* A CMObjectID for some hardware implementations may NOT be exactly 4 bytes (but it    */
  468.     /* better be at least 4 bytes).  A user's "reference" data is always 4 bytes because    */
  469.     /* we define such data here as an object ID.  We must take care to convert the                 */
  470.     /* internal, i.e., hardware, representation to that of a container representation.    */
  471.     /* we just happen to have a handler     */
  472.     /* that does this conversion.                                                                                                                    */
  473.     
  474.     CMformatData(container, theReferenceData, 4, &((TOCObjectPtr)referencedObject)->objectID);
  475.     
  476.     return ((CMReference *)theReferenceData);                /* return the ptr to the "reference"    */
  477. }
  478.  
  479.  
  480. /*-----------------------------------------------------------------------*
  481.  | CMGetReferencedObject - retrieve a object (refNum) from a "reference" |
  482.  *-----------------------------------------------------------------------*
  483.  
  484.  Converts an object "reference", created by CMGetReferenceData(), back to an object refNum,
  485.  from the data supplied by the specified value.
  486. */
  487.  
  488. CMObject CM_FIXEDARGS CMGetReferencedObject(CMValue value, CMReference CM_PTR theReferenceData)
  489. {
  490.     ContainerPtr container;
  491.     CMObjectID     objectID;
  492.     TOCObjectPtr theObject;
  493.     CM_CHAR          idStr[15];
  494.  
  495.     ExitIfBadValue(value, NULL);                                                            /* validate value                        */
  496.     
  497.     container = ((TOCValueHdrPtr)value)->container;
  498.     
  499.     /* Use handler to convert external representation back to internal representation.         */
  500.     /* See comments in CMGetReferenceData() why we do this.                                                                */
  501.     
  502.     CMextractData(container, theReferenceData, 4, &objectID);    /* get "reference" object ID*/
  503.     
  504.     theObject = cmFindObject(container->toc, objectID);                /* get the "refNum"                    */
  505.     if (theObject == NULL)                                                                        /* huh?                                            */
  506.     {    Container_Disable(container);
  507.         ERROR2(CM_err_UndefReference, cmltostr(objectID, 1, false, idStr), CONTAINERNAME);
  508.     }    
  509.     ++theObject->useCount;                                                                        /* count this use of the obj*/
  510.     
  511.     return ((CMObject)theObject);                                                            /* give back the refNum            */
  512. }
  513. #endif
  514.  
  515.  
  516. /*------------------------------------------------------------------------*
  517.  | CMGetObjectContainer - get the container refNum for one of its objects |
  518.  *------------------------------------------------------------------------*
  519.  
  520.  The refNum for the container which contains the specified object is returned.
  521. */
  522.  
  523. CMContainer CM_FIXEDARGS CMGetObjectContainer(CMObject theObject)
  524. {
  525.     ExitIfBadObject(theObject, NULL);                                /* validate theObject                                    */
  526.  
  527.     return ((CMContainer)(((TOCObjectPtr)theObject)->container));
  528. }
  529.  
  530.  
  531. /*---------------------------------------------------------*
  532.  | checkValue - check a value to see if it's a global name |
  533.  *---------------------------------------------------------*
  534.  
  535.  This is a cmWalkObject() action routine initiated by CMGetGlobalName() below to find the
  536.  global name value in an object.  The "refCon" is a pointer to a GetGNameComArea
  537.  communication area where we will save the value pointer.  We also count the number of
  538.  global names seen in the object.  It shoould be 1.  But we walk the entire object just to
  539.  be sure.
  540.  
  541.  Note, this "static" is intentionally left to default memory model under DOS since it is
  542.  passed as a function pointer to cmWalkObject().
  543. */
  544.  
  545. static TOCWalkReturns checkValue(ContainerPtr container, TOCValuePtr theValue, CMRefCon refCon)
  546. {
  547.     GetGNameComAreaPtr g = (GetGNameComAreaPtr)refCon;
  548.     ContainerPtr             unused = container;
  549.     
  550.     if (theValue->flags & kCMGlobalName) {
  551.         g->theValue = theValue;                                                    /* save global name ptr                            */
  552.         ++g->nbrOfGlobalNames;                                                    /* count it too                                            */
  553.     }
  554.     
  555.     return (WalkNextTOCValue);                                                /* continue value walk                            */
  556. }
  557.  
  558.  
  559. /*--------------------------------------------------------------------*
  560.  | CMGetGlobalName - get the global name (string) value for an object |
  561.  *--------------------------------------------------------------------*
  562.  
  563.  This routine takes an object refNum and searches its values to see if it has a global
  564.  name (defined by CMRegisterType() or CMRegisterProperty()).  If it does, a pointer to
  565.  the global name string is returned.  If none is found, NULL is returned.
  566.  
  567.  Caution: the user must treat the returned pointer as a value pointing to a read-only
  568.           entity!  The pointer we return here is a pointer directly to the name string
  569.                     in the global name symbol table.  There is no enforcement of this (how?).
  570. */
  571.  
  572. CMGlobalName CM_FIXEDARGS CMGetGlobalName(CMObject theObject)
  573. {
  574.     TOCValuePtr             theValue;
  575.     GetGNameComArea gNameComArea;
  576.     ContainerPtr        container;
  577.  
  578.     ExitIfBadObject(theObject, NULL);                                /* validate theObject                                    */
  579.     
  580.     container = ((TOCObjectPtr)theObject)->container;
  581.  
  582.     /* Walk the entire object and look at all the values to find the value for a global        */
  583.     /* name.  The object can have other properties and values, but there better be only     */
  584.     /* one global name.  The object is walked with cmWalkObject().  The "refCon" we pass    */
  585.     /* is a pointer to a communication area which will hold the count of the global name    */
  586.     /* values and the pointer to it.  As just mentioned, if the count comes back other         */
  587.     /* than 1, we have an error.                                                                                                                    */
  588.     
  589.     gNameComArea.theValue = NULL;                                        /* init value ptr to no value yet            */
  590.     gNameComArea.nbrOfGlobalNames = 0;                            /* there are no global names yet too    */
  591.     
  592.     cmWalkObject(container, (TOCObjectPtr)theObject, &gNameComArea, NULL, NULL, NULL, checkValue);
  593.     
  594.     /* After the walk we should have found 1 or 0 global names. If there is more than 1     */
  595.     /* we have an ambiguity.  0 means return NULL.                                                                                */
  596.         
  597.     if (gNameComArea.nbrOfGlobalNames > 1) {                /* must have exactly 1 global name        */
  598.         Container_Disable(container);
  599.         ERROR2(CM_err_AmbiguousType, "CMGetGlobalName", CONTAINERNAME);
  600.         return (NULL);
  601.     }
  602.  
  603.     if (gNameComArea.nbrOfGlobalNames == 0)                    /* no name ==> NULL return                        */
  604.         return (NULL);
  605.     
  606.     theValue = gNameComArea.theValue;
  607.     if (theValue == NULL) return (NULL);                        /* safety                                                            */
  608.     
  609.     return ((CMGlobalName)GetGlobalName(theValue->value.globalName.globalNameSymbol));
  610. }
  611.  
  612. /*-----------------------------------------------------------------*
  613.  | CMCountProperties - count the number of properties in an object |
  614.  *-----------------------------------------------------------------*
  615.  
  616.  An object can be defined to have any number of properties.  The properties for a given 
  617.  object are unique.  This routine is used to determine the total number of properties 
  618.  for an object or whether a property is present in that object.
  619.  
  620.  If the property is specified as NULL, the total number of properties in the object
  621.  is returned.  If the property is not NULL, 1 is returned if that property is present
  622.  (because there can be a maximum of one value of that type), and 0 otherwise.
  623. */
  624.  
  625. CMCount CM_FIXEDARGS CMCountProperties(CMObject object, CMProperty property)
  626. {
  627.     ContainerPtr      container;
  628.     
  629.     ExitIfBadObject(object, 0);                                                /* validate object                                    */
  630.     
  631.     container = ((TOCObjectPtr)object)->container;
  632.     
  633.     /* Process explicitly specified type separately...                                                                        */
  634.     
  635.     if (property != NULL) {
  636.         ExitIfBadProperty(property, 0);                            /* validate property                                        */
  637.  
  638.         { ContainerPtr other = ((TOCObjectPtr)property)->container;
  639.             if (container->targetContainer != other->targetContainer) {
  640.                 Container_Disable(container);
  641.                 Container_Disable(other);
  642.                 ERROR2(CM_err_2Containers, CONTAINERNAMEx(container),
  643.                                                                      CONTAINERNAMEx(other));
  644.                 return (0);
  645.             }
  646.         }
  647.         
  648.         /* Find the TOCProperty belonging to the object with the property ID of the                    */
  649.         /* specified property object...                                                                                                            */
  650.     
  651.         return ((CMCount)(cmGetObjectProperty((TOCObjectPtr)object,
  652.                                                                           ((TOCObjectPtr)property)->objectID) != NULL));
  653.     }
  654.     
  655.     /* From here on we're interested in just the total number of properties...                        */
  656.     
  657.     return ((CMCount)cmCountListCells(&((TOCObjectPtr)object)->propertyList));
  658. }
  659.  
  660. /*---------------------------------------------------*
  661.  | CMGetObjectRefCon - return user's object "refCon" |
  662.  *---------------------------------------------------*
  663.  
  664.  This routine returns the user's "refCon" (reference constant) that s/he may associate
  665.  with any object refNum (i.e., a CMObject).  The refCon is a CM_ULONG that the user may use
  666.  in any way.  It is not touched by the API except to init it to 0 when the object is
  667.  initially created.
  668.  
  669.  Note, the refCon is NOT perserved across closed containers, i.e., it is not saved in the
  670.  TOC.
  671. */
  672.  
  673. CMRefCon CM_FIXEDARGS CMGetObjectRefCon(CMObject theObject)
  674. {
  675.     ExitIfBadObject(theObject, (CMRefCon)NULL);                            /* validate theObject                    */
  676.     
  677.     return (((TOCObjectPtr)theObject)->objectRefCon);                /* return user's refCon                */
  678. }
  679.  
  680.  
  681. /*----------------------------------------------------*
  682.  | CMSetObjectRefCon - set the user's object "refCon" |
  683.  *----------------------------------------------------*
  684.  
  685.  This routine is used to set the user's "refCon" (reference constant) to be assoicated with
  686.  an object.  The refCon is a CM_ULONG that the user may use in any way.  It is not touched
  687.  by the API.
  688.  
  689.  Note, the refCon is NOT perserved across closed containers, i.e., it is not saved in the
  690.  TOC.
  691. */
  692.  
  693. void CM_FIXEDARGS CMSetObjectRefCon(CMObject theObject, CMRefCon refCon)
  694. {
  695.     ExitIfBadObject(theObject, CM_NOVALUE);                                    /* validate theObject                    */
  696.     
  697.     ((TOCObjectPtr)theObject)->objectRefCon = refCon;                /* set the user's refCon            */
  698. }
  699.  
  700.  
  701. /*-----------------------------------*
  702.  | CMDeleteObject - delete an object |
  703.  *-----------------------------------*
  704.  
  705.  The specified object and all its properties and values are deleted.  It is an error to
  706.  use this object (refNum) from this point on.  Deleted objects no longer exist.  The
  707.  CMGetNext... routines will also never return them.
  708.  
  709.  Note, some objects are protected from deletion.  This includes the predefined TOC
  710.  objects (seed and offset values) and objects representing currently opened embedded
  711.  containers. 
  712. */
  713.  
  714. void CM_FIXEDARGS CMDeleteObject(CMObject theObject)
  715. {
  716.     ContainerPtr container;
  717.     
  718.     ExitIfBadObject(theObject, CM_NOVALUE);                            /* validate theObject                            */
  719.     
  720.     container = ((TOCObjectPtr)theObject)->container->updatingContainer;
  721.     
  722.     if ((container->useFlags & kCMWriting) == 0) {            /* make sure opened for writing        */
  723.         Container_Disable(container);
  724.         ERROR2(CM_err_DeleteIllegal, "object", CONTAINERNAME);
  725.         return;
  726.     }
  727.  
  728.     if (((TOCObjectPtr)theObject)->useCount > 1) {            /* there are other users!                    */
  729.         Container_Disable(container);
  730.         ERROR1(CM_err_CantDelete6, CONTAINERNAME);
  731.         return;
  732.     }
  733.     
  734.     ((TOCObjectPtr)theObject)->useCount = 0;                        /* no longer in use (obviously)        */
  735.     
  736.     /* It is an error to delete a protected object (e.g., object ID 1) or an object             */
  737.     /* containing dynamic values.  But if it's not one of these, delete the object. If        */
  738.     /* we're recording updates, then define touched list entry for the delete...                    */
  739.     
  740.     if (((TOCObjectPtr)theObject)->objectFlags & ProtectedObject)
  741.     {    Container_Disable(container);
  742.         ERROR1(CM_err_CantDelete1, CONTAINERNAME);
  743.     }
  744.     else if (((TOCObjectPtr)theObject)->objectFlags & DynamicValuesObject)
  745.     {    Container_Disable(container);
  746.         ERROR1(CM_err_CantDelete5, CONTAINERNAME);
  747.     }
  748.     else {
  749.         cmMarkObjectDeleted(container, (TOCObjectPtr)theObject);
  750.         cmTouchDeletedObject((TOCObjectPtr)theObject);         /* must call AFTER marking                */
  751.     }
  752. }
  753.  
  754.  
  755. /*------------------------------------------------------------*
  756.  | CMDeleteObjectProperty - delete a property of an an object |
  757.  *------------------------------------------------------------*
  758.  
  759.  The property corresponding to the object ID of theProperty is deleted along with all of 
  760.  its values.
  761.  
  762.  Note, some property values are protected from deletion.  This includes the predefined
  763.  TOC object values (seed and offset) and the currently open embedded container values.
  764. */
  765.  
  766. void CM_FIXEDARGS CMDeleteObjectProperty(CMObject theObject, CMProperty theProperty)
  767. {
  768.     ContainerPtr      container;
  769.     TOCValueHdrPtr theValueHdr;
  770.  
  771.     ExitIfBadObject(theObject, CM_NOVALUE);                    /* validate theObject                                    */
  772.     ExitIfBadProperty(theProperty,CM_NOVALUE);            /* validate theProperty                                */
  773.     
  774.     container = ((TOCObjectPtr)theObject)->container;
  775.     
  776.     { ContainerPtr other = ((TOCObjectPtr)theProperty)->container;
  777.         if (container->targetContainer != other->targetContainer) {
  778.             Container_Disable(container);
  779.             Container_Disable(other);
  780.             ERROR2(CM_err_2Containers, CONTAINERNAMEx(container),
  781.                                                                  CONTAINERNAMEx(other));
  782.             return;
  783.         }
  784.     }
  785.  
  786.     container = container->updatingContainer;                /* use updating container from here on*/
  787.     
  788.     if ((container->useFlags & kCMWriting) == 0) {
  789.         Container_Disable(container);
  790.         ERROR2(CM_err_DeleteIllegal, "object's property", CONTAINERNAME);
  791.         return;
  792.     }
  793.     
  794.     /* Search through the properties for this object looking for the one that has the            */
  795.     /* ID as the passed property descriptor object. Note we store back into theProperty        */
  796.     /* (the variable) thus changing its meaning and type.    I just thought I would point         */
  797.     /* that out explicitly!                                                                                                                                */
  798.     
  799.     theProperty = (CMProperty)cmGetObjectProperty((TOCObjectPtr)theObject,
  800.                                                                                                 ((TOCObjectPtr)theProperty)->objectID);
  801.     if (theProperty == NULL) return;                                /* exit if property not in object            */
  802.     
  803.     /* Scan the values (headers) for this property to make sure there are no protected        */
  804.     /* values.  These are values which we never want deleted.  If there are any then it     */
  805.     /* is an error to delete this property from the object.  Sorry about that!                        */
  806.     
  807.     theValueHdr = (TOCValueHdrPtr)cmGetListHead(&((TOCPropertyPtr)theProperty)->valueHdrList);
  808.     while (theValueHdr) {
  809.         if ((theValueHdr->valueFlags & ValueProtected) != 0){    /* can't delete if protected!    */
  810.             Container_Disable(container);
  811.             ERROR1(CM_err_CantDelete2, CONTAINERNAME);
  812.             return;
  813.         }
  814.         theValueHdr = (TOCValueHdrPtr)cmGetNextListCell(theValueHdr);
  815.     } /* while */
  816.  
  817.     /* If we're recording updates, then define touched list entry for the delete...                */
  818.     
  819.     cmTouchDeletedProperty((TOCPropertyPtr)theProperty, ((TOCPropertyPtr)theProperty)->theObject);
  820.         
  821.     cmDeleteProperty(container, (TOCPropertyPtr)theProperty);
  822. }
  823.  
  824.  
  825. /*------------------------------------------------------------------------*
  826.  | CMReleaseObject - destroy association between an object and its refNum |
  827.  *------------------------------------------------------------------------*
  828.  
  829.  The association between the refNum and the object is destroyed. There should be no further
  830.  operations with the object (refNum) once this routine is called.
  831. */
  832.  
  833. void CM_FIXEDARGS CMReleaseObject(CMObject theObject)
  834. {
  835.     ContainerPtr container;
  836.     
  837.     ExitIfBadObject(theObject, CM_NOVALUE);                    /* validate theObject                                    */
  838.     
  839.     if (((TOCObjectPtr)theObject)->useCount == 0) {    /* error if already fully released        */
  840.         container = ((TOCObjectPtr)theObject)->container;
  841.         Container_Disable(container);
  842.         ERROR1(CM_err_AlreadyReleased2, CONTAINERNAME);
  843.     } else
  844.         --((TOCObjectPtr)theObject)->useCount;                /* decrement the object's use count        */
  845. }
  846.  
  847. CMObject CM_FIXEDARGS CMGetObject(CMContainer targetContainer, CMObjectID objectID)
  848. {
  849.     ContainerPtr container = (ContainerPtr)targetContainer;
  850.     TOCObjectPtr    object;
  851.     
  852.     object = cmFindObject(container->toc, objectID);
  853.     if (object != NULL)
  854.         ++object->useCount;
  855.     
  856.     return (CMObject) object;
  857. }
  858.     
  859. CMObjectID CM_FIXEDARGS CMGetObjectID(CMObject object)
  860. {
  861.     return ((TOCObjectPtr) object)->objectID;
  862. }
  863.     
  864.                                                           
  865.                                                             CM_END_CFUNCTIONS
  866.